/**
 * http请求
 */
import Singleton from "./Singleton";
import { Config, env } from "./HttpConfig";
import PopupManager from '../core/PopupManager'
import LogUtil from "../utils/LogUtil";
import { Utils } from "../utils/Utils";
import { NetInfo } from "./Commond";

enum HttpCode {
    kSuccess = 0,
    kTimeout = 10000,
    kUnknown = 10001,
    kAbort = 10002,
    kError = 10003,
    kSessionTimeout = -8,
    kIAmInBlocklist = -3013,
    kUserIsInMyBlocklist = -3014
}

type HttpRequestType = 'post' | 'get'

export class HttpRequest extends Singleton {

    //错误返回
    private errCb: Function = null

    /**
     * 获取服务器地址
     * @param url 
     * @returns 
     */
    private getUrl(url: string = ''): string {
        if (url.indexOf('http') != -1) return '';
        if (Config.environment == env.test) {
            return  `http://${NetInfo.ip}:${NetInfo.port}`;
        } else if (Config.environment == env.uat) {
            return '';
        } else {
            return '';
        }
    }

    /**
     * 请求参数拼接
     * @param params 
     * @returns 
     */
    private getQueryString(params: object) {
        const tmps: string[] = [];
        for (let key in params) {
            tmps.push(`${key}=${params[key]}`);
        }
        return tmps.join("&");
    }

    /**
     * http异步请求
     * @param cmd 
     * @param param 
     * @param type 
     * @param errorBack 
     * @returns 
     */
    httpPromise(cmd: string, param: object, type: HttpRequestType, errorBack: Function = null) {
        return new Promise((resolve, reject) => {
            if (type == 'post') {
                this.sendPost(cmd, param, (response) => {
                    if (response != null) {
                        resolve(response);
                    } else {
                        reject(new Error(cmd + ' Error !'));
                    }
                }, errorBack);
            } else if (type == 'get') {
                this.sendGet(cmd, param, (response) => {
                    if (response != null) {
                        resolve(response);
                    } else {
                        reject(new Error(cmd + ' Error !'));
                    }
                }, errorBack);
            }
        });
    }

    /**
    * @param name 指令名称
    * @param params 指令参数
    * @param cb 回调函数，推荐使用()=>{}
    * @param errCb 错误回调
    * @returns 
    */
    sendGet(name: string, params: object, cb: Function, errCb: Function = null) {
        this.errCb = errCb
        let url = this.getUrl(name) + name
        if (params) {
            if (url.indexOf("?") == -1) {
                url += "?";
            }
            url += this.getQueryString(params);
        }
        return this.sendHttp(url, null, "GET", cb);
    }

    /**
    * 
    * @param name 指令名称
    * @param params 指令参数
    * @param cb 回调函数，推荐使用()=>{}
    * @param errCb 错误回调
    * @returns 
    */
    sendPost(name: string, params: object, cb: Function = null, errCb: Function = null) {
        this.errCb = errCb
        return this.sendHttp(this.getUrl(name) + name, params, "POST", cb);
    }

    private sendHttp(url: string, params: object, method: string, cb: Function) {
        const xhr = cc.loader.getXMLHttpRequest();
        xhr.responseType = 'text';
        xhr.timeout = 5000;
        xhr.onreadystatechange = this.onReadyStateChange.bind(this, xhr, cb);
        xhr.ontimeout = this.onTimeout.bind(this, xhr, url);
        xhr.onerror = this.onError.bind(this, xhr, url);
        xhr.onabort = this.onAbort.bind(this, xhr, url);
        xhr.open(method, url, true);
        // this.setHttpHeaders(xhr, { 'Content-Type': 'application/json' })
        // this.setHttpHeaders(xhr, { 'Accept': 'application/json' });
        // this.setHttpHeaders(xhr, { 'App-Name': 'TestPC' });
        // this.setHttpHeaders(xhr, { 'App-Version': '1.0.0' });
        // this.setHttpHeaders(xhr, { 'Api-Version': '1.0.0' });
        // this.setHttpHeaders(xhr, { 'accessToken': 'token' });
        if (params && typeof params === 'object') {
            var _params = JSON.stringify(params);
        }
        xhr.send(_params);
        return xhr;
    }

    private setHttpHeaders(xhr: XMLHttpRequest, headers) {
        for (let key in headers) {
            xhr.setRequestHeader(key, headers[key]);
        }
    }

    private onReadyStateChange(xhr: XMLHttpRequest, cb: Function) {
        // LogUtil.log("HttpService, onReadyStateChange, readyState=", xhr.readyState, "status = ", xhr.status, "responseText =", xhr.responseText);
        if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status < 300) {
            let data;
            let code = HttpCode.kUnknown;
            let msg: string = "";
            const response = Utils.JsonParse(xhr.responseText);
            if (response && response.code) {
                code = response.code;
                data = response.data;
                msg = response.msg;
            }
            else {
                code = HttpCode.kSuccess;
                data = response;
            }
            this.notifyCallback(cb, code, data, msg);
            this.removeXhrEvent(xhr);
        }
    }

    private onTimeout(xhr: XMLHttpRequest, url: string) {
        LogUtil.warn(url, "requst onTimeOut");
        this.removeXhrEvent(xhr);
        // this._showToast(HttpCode.kTimeout);
        let desc = "请求超时，重新请求吧！";
        if (Config.environment == env.local || Config.environment == env.test) {
            desc = desc + "url=" + url;
        }
        this._showToast(desc);
    }

    private onError(xhr: XMLHttpRequest, url: string) {
        LogUtil.warn(url, "request onError");
        this.removeXhrEvent(xhr);
        // this._showToast(HttpCode.kError);
        let desc = "接口出错啦，重新请求吧！";
        if (Config.environment == env.local || Config.environment == env.test) {
            desc = desc + "url=" + url;
        }
        this._showToast(desc);
    }

    private onAbort(xhr: XMLHttpRequest, url: string) {
        LogUtil.warn(url, "request onAbort");
        this.removeXhrEvent(xhr);
        this._showToast(HttpCode.kAbort);
    }

    private _showToast(code: string | number) {
        let des = '网络不给力,code:' + code;
        if(typeof code == "string"){
            des = code;
        }
        PopupManager.show('prefabs/PopBox', {
            title: '提示',
            content: des
        });
        this.errCb && this.errCb();
        // UIManager.ins().showMessage('网络不给力,code:' + code);
    }

    private removeXhrEvent(xhr: XMLHttpRequest) {
        xhr.ontimeout = null;
        xhr.onerror = null;
        xhr.onabort = null;
        xhr.onreadystatechange = null;
    }

    private notifyCallback(cb: Function, code: number, data: object, msg: string) {
        if (cb) {
            if (code == 0) {  //与服务端商定不为0时全弹窗
                cb(data, code, msg);
            } else {
                this.errCb && this.errCb();
                PopupManager.show('prefabs/PopBox', {
                    title: '提示',
                    content: msg
                });
            }
        }
    }
}
